/**
 * glslutils, for color translate matrix
 * reference: http://graficaobscura.com/matrix/index.html
 * @autohr HALX99 2016
 * Copyright (c) x-studio365 2016.
 */
#ifndef _GLSLUTILS_H_
#define _GLSLUTILS_H_
#include "matrix3f.hpp"
#include "cocos2d.h"
#include <string>
typedef float _M3X3[3][3];
typedef float _M4X4[4][4];

static cocos2d::Vec3 fastest_rgb2hsv(const cocos2d::Color3B& rgb)
{
    float r = rgb.r / 255.0f;
    float g = rgb.g / 255.0f;
    float b = rgb.b / 255.0f;

    float h, s, v;

    float K = 0.f;

    if (g < b)
    {
        std::swap(g, b);
        K = -1.f;
    }

    if (r < g)
    {
        std::swap(r, g);
        K = -2.f / 6.f - K;
    }

    float chroma = r - std::min(g, b);
    h = fabs(K + (g - b) / (6.f * chroma + 1e-20f));
    s = chroma / (r + 1e-20f);
    v = r;

    return cocos2d::Vec3(h, s, v);
}

static cocos2d::Vec3 rgb2hsv(const cocos2d::Color3B& rgb)
{
    unsigned char dst_h, dst_s, dst_v;

    float r = rgb.r / 255.0f;
    float g = rgb.g / 255.0f;
    float b = rgb.b / 255.0f;

    float h, s, v; // h:0-360.0, s:0.0-1.0, v:0.0-1.0

    float max = std::max({ r, g, b });
    float min = std::min({ r, g, b });

    v = max;

    if (max == 0.0f) {
        s = 0;
        h = 0;
    }
    else if (max - min == 0.0f) {
        s = 0;
        h = 0;
    }
    else {
        s = (max - min) / max;

        if (max == r) {
            h = 60 * ((g - b) / (max - min)) + 0;
        }
        else if (max == g) {
            h = 60 * ((b - r) / (max - min)) + 120;
        }
        else {
            h = 60 * ((r - g) / (max - min)) + 240;
        }
    }

    if (h < 0) h += 360.0f;

    dst_h = (unsigned char)(h / 2);   // dst_h : 0-180
    dst_s = (unsigned char)(s/* * 255*/); // dst_s : 0-255
    dst_v = (unsigned char)(v /** 255*/); // dst_v : 0-255

    return cocos2d::Vec3(dst_h / 180.f, dst_s, dst_v);
}

static void hsv2rgb(const unsigned char &src_h, const unsigned char &src_s, const unsigned char &src_v, unsigned char &dst_r, unsigned char &dst_g, unsigned char &dst_b)
{
    float h = src_h *   2.0f; // 0-360
    float s = src_s / 255.0f; // 0.0-1.0
    float v = src_v / 255.0f; // 0.0-1.0

    float r, g, b; // 0.0-1.0

    int   hi = (int)(h / 60.0f) % 6;
    float f = (h / 60.0f) - hi;
    float p = v * (1.0f - s);
    float q = v * (1.0f - s * f);
    float t = v * (1.0f - s * (1.0f - f));

    switch (hi) {
    case 0: r = v, g = t, b = p; break;
    case 1: r = q, g = v, b = p; break;
    case 2: r = p, g = v, b = t; break;
    case 3: r = p, g = q, b = v; break;
    case 4: r = t, g = p, b = v; break;
    case 5: r = v, g = p, b = q; break;
    }

    dst_r = (unsigned char)(r * 255); // dst_r : 0-255
    dst_g = (unsigned char)(g * 255); // dst_r : 0-255
    dst_b = (unsigned char)(b * 255); // dst_r : 0-255
}

namespace glslutils
{
#define FLT_SQRT_2 1.4142135623730950488016887242097
#define FLT_SQRT_3 1.7320508075688772935274463415059
#define FLT_XRS (1 / FLT_SQRT_2)
#define FLT_XRC FLT_XRS
#define FLT_YRS (-1 / FLT_SQRT_3)
#define FLT_YRC (FLT_SQRT_2 / FLT_SQRT_3)
#define RLUM    (0.3086)
#define GLUM    (0.6094)
#define BLUM    (0.0820)


    static void printmat3(float mat[3][3])
    {
        int x, y;
        char svalue[256];
        int n = 0;
        for (y = 0; y < 3; y++) {
            for (x = 0; x < 3; x++)
                n += sprintf(svalue + n, "%f ", mat[y][x]);
            n += sprintf(svalue + n, "\n");
        }
        n += sprintf(svalue + n, "\n");

        cocos2d::log("%s", svalue);
    }

    static void printmat4(float mat[4][4])
    {
        int x, y;
        char svalue[256];
        int n = 0;
        for (y = 0; y < 4; y++) {
            for (x = 0; x < 4; x++)
                n += sprintf(svalue + n, "%f ", mat[y][x]);
            n += sprintf(svalue + n, "\n");
        }
        n += sprintf(svalue + n, "\n");

        cocos2d::log("%s", svalue);
    }

    inline void printmat3(float(&mat)[9])
    {
        printmat3((_M3X3&)mat);
    }

    inline void printmat4(float(&mat)[16])
    {
        printmat4((_M4X4&)mat);
    }

    inline void createRotationX(cocos2d::Mat4* dst, float sv, float cv)
    {
        dst->m[5] = cv;
        dst->m[6] = sv;
        dst->m[9] = -sv;
        dst->m[10] = cv;
    }

    inline void createRotationY(cocos2d::Mat4* dst, float sv, float cv)
    {
        dst->m[0] = cv;
        dst->m[2] = -sv;
        dst->m[8] = sv;
        dst->m[10] = cv;
    }

    inline void createRotationZ(cocos2d::Mat4* dst, float sv, float cv)
    {
        dst->m[0] = cv;
        dst->m[1] = sv;
        dst->m[4] = -sv;
        dst->m[5] = cv;
    }

    inline void rotateX(cocos2d::Mat4* dst, float sv, float cv)
    {
        cocos2d::Mat4 temp;
        createRotationX(&temp, sv, cv);
        cocos2d::Mat4::multiply(temp, *dst, dst);
    }

    inline void rotateY(cocos2d::Mat4* dst, float sv, float cv)
    {
        cocos2d::Mat4 temp;
        createRotationY(&temp, sv, cv);
        cocos2d::Mat4::multiply(temp, *dst, dst); // dst->multiply(temp); pitfall: matrix1 * matrix2 != matrix2 * matrix1
    }

    inline void rotateZ(cocos2d::Mat4* dst, float sv, float cv)
    {
        cocos2d::Mat4 temp;
        createRotationZ(&temp, sv, cv);
        cocos2d::Mat4::multiply(temp, *dst, dst);
    }

    inline void rotateZ(cocos2d::Mat4* dst, float angle)
    {
        cocos2d::Mat4 temp;
        cocos2d::Mat4::createRotationZ(angle, &temp);
        cocos2d::Mat4::multiply(temp, *dst, dst);
    }

    /*
    *    matrixmult -
    *        multiply two matricies
    */
    static void matrixmult(float a[4][4], float b[4][4], float c[4][4])
    {
        int x, y;
        float temp[4][4];

        for (y = 0; y < 4; y++)
            for (x = 0; x < 4; x++) {
                temp[y][x] = b[y][0] * a[0][x]
                    + b[y][1] * a[1][x]
                    + b[y][2] * a[2][x]
                    + b[y][3] * a[3][x];
            }
        for (y = 0; y < 4; y++)
            for (x = 0; x < 4; x++)
                c[y][x] = temp[y][x];
    }

    /*
    *    identmat -
    *        make an identity matrix
    */
    inline void identmat(float *matrix)
    {
        *matrix++ = 1.0;    /* row 1        */
        *matrix++ = 0.0;
        *matrix++ = 0.0;
        *matrix++ = 0.0;
        *matrix++ = 0.0;    /* row 2        */
        *matrix++ = 1.0;
        *matrix++ = 0.0;
        *matrix++ = 0.0;
        *matrix++ = 0.0;    /* row 3        */
        *matrix++ = 0.0;
        *matrix++ = 1.0;
        *matrix++ = 0.0;
        *matrix++ = 0.0;    /* row 4        */
        *matrix++ = 0.0;
        *matrix++ = 0.0;
        *matrix++ = 1.0;
    }

    /*
    *    xformpnt -
    *        transform a 3D point using a matrix
    */
    inline void xformpnt(float matrix[4][4], float x, float y, float z, float *tx, float *ty, float *tz)
    {
        *tx = x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + matrix[3][0];
        *ty = x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + matrix[3][1];
        *tz = x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + matrix[3][2];
    }

    /*
    *    cscalemat -
    *        make a color scale marix
    */
    inline void cscalemat(float mat[4][4], float rscale, float gscale, float bscale)
    {
        float mmat[4][4];

        mmat[0][0] = rscale;
        mmat[0][1] = 0.0;
        mmat[0][2] = 0.0;
        mmat[0][3] = 0.0;

        mmat[1][0] = 0.0;
        mmat[1][1] = gscale;
        mmat[1][2] = 0.0;
        mmat[1][3] = 0.0;


        mmat[2][0] = 0.0;
        mmat[2][1] = 0.0;
        mmat[2][2] = bscale;
        mmat[2][3] = 0.0;

        mmat[3][0] = 0.0;
        mmat[3][1] = 0.0;
        mmat[3][2] = 0.0;
        mmat[3][3] = 1.0;
        matrixmult(mmat, mat, mat);
    }

    /*
    *    lummat -
    *        make a luminance marix
    */
    inline void lummat(float mat[4][4])
    {
        float mmat[4][4];
        float rwgt, gwgt, bwgt;

        rwgt = RLUM;
        gwgt = GLUM;
        bwgt = BLUM;
        mmat[0][0] = rwgt;
        mmat[0][1] = rwgt;
        mmat[0][2] = rwgt;
        mmat[0][3] = 0.0;

        mmat[1][0] = gwgt;
        mmat[1][1] = gwgt;
        mmat[1][2] = gwgt;
        mmat[1][3] = 0.0;

        mmat[2][0] = bwgt;
        mmat[2][1] = bwgt;
        mmat[2][2] = bwgt;
        mmat[2][3] = 0.0;

        mmat[3][0] = 0.0;
        mmat[3][1] = 0.0;
        mmat[3][2] = 0.0;
        mmat[3][3] = 1.0;
        matrixmult(mmat, mat, mat);
    }

    /*
    *    saturatemat -
    *        make a saturation marix
    */
    inline void saturatemat(float mat[4][4], float sat)
    {
        float mmat[4][4];
        float a, b, c, d, e, f, g, h, i;
        float rwgt, gwgt, bwgt;

        rwgt = RLUM;
        gwgt = GLUM;
        bwgt = BLUM;

        a = (1.0 - sat)*rwgt + sat;
        b = (1.0 - sat)*rwgt;
        c = (1.0 - sat)*rwgt;
        d = (1.0 - sat)*gwgt;
        e = (1.0 - sat)*gwgt + sat;
        f = (1.0 - sat)*gwgt;
        g = (1.0 - sat)*bwgt;
        h = (1.0 - sat)*bwgt;
        i = (1.0 - sat)*bwgt + sat;
        mmat[0][0] = a;
        mmat[0][1] = b;
        mmat[0][2] = c;
        mmat[0][3] = 0.0;

        mmat[1][0] = d;
        mmat[1][1] = e;
        mmat[1][2] = f;
        mmat[1][3] = 0.0;

        mmat[2][0] = g;
        mmat[2][1] = h;
        mmat[2][2] = i;
        mmat[2][3] = 0.0;

        mmat[3][0] = 0.0;
        mmat[3][1] = 0.0;
        mmat[3][2] = 0.0;
        mmat[3][3] = 1.0;
        matrixmult(mmat, mat, mat);
    }

    /*
    *    offsetmat -
    *        offset r, g, and b
    */
    inline void offsetmat(float mat[4][4], float roffset, float goffset, float boffset)
    {
        float mmat[4][4];

        mmat[0][0] = 1.0;
        mmat[0][1] = 0.0;
        mmat[0][2] = 0.0;
        mmat[0][3] = 0.0;

        mmat[1][0] = 0.0;
        mmat[1][1] = 1.0;
        mmat[1][2] = 0.0;
        mmat[1][3] = 0.0;

        mmat[2][0] = 0.0;
        mmat[2][1] = 0.0;
        mmat[2][2] = 1.0;
        mmat[2][3] = 0.0;

        mmat[3][0] = roffset;
        mmat[3][1] = goffset;
        mmat[3][2] = boffset;
        mmat[3][3] = 1.0;
        matrixmult(mmat, mat, mat);
    }

    /*
    *    xrotate -
    *        rotate about the x (red) axis
    */
    inline void xrotatemat(float mat[4][4], float rs, float rc)
    {
        float mmat[4][4];

        mmat[0][0] = 1.0;
        mmat[0][1] = 0.0;
        mmat[0][2] = 0.0;
        mmat[0][3] = 0.0;

        mmat[1][0] = 0.0;
        mmat[1][1] = rc;
        mmat[1][2] = rs;
        mmat[1][3] = 0.0;

        mmat[2][0] = 0.0;
        mmat[2][1] = -rs;
        mmat[2][2] = rc;
        mmat[2][3] = 0.0;

        mmat[3][0] = 0.0;
        mmat[3][1] = 0.0;
        mmat[3][2] = 0.0;
        mmat[3][3] = 1.0;
        matrixmult(mmat, mat, mat);
    }

    /*
    *    yrotate -
    *        rotate about the y (green) axis
    */
    inline void yrotatemat(float mat[4][4], float rs, float rc)
    {
        float mmat[4][4];

        mmat[0][0] = rc;
        mmat[0][1] = 0.0;
        mmat[0][2] = -rs;
        mmat[0][3] = 0.0;

        mmat[1][0] = 0.0;
        mmat[1][1] = 1.0;
        mmat[1][2] = 0.0;
        mmat[1][3] = 0.0;

        mmat[2][0] = rs;
        mmat[2][1] = 0.0;
        mmat[2][2] = rc;
        mmat[2][3] = 0.0;

        mmat[3][0] = 0.0;
        mmat[3][1] = 0.0;
        mmat[3][2] = 0.0;
        mmat[3][3] = 1.0;
        matrixmult(mmat, mat, mat);
    }

    /*
    *    zrotate -
    *        rotate about the z (blue) axis
    */
    inline void zrotatemat(float mat[4][4], float rs, float rc)
    {
        float mmat[4][4];

        mmat[0][0] = rc;
        mmat[0][1] = rs;
        mmat[0][2] = 0.0;
        mmat[0][3] = 0.0;

        mmat[1][0] = -rs;
        mmat[1][1] = rc;
        mmat[1][2] = 0.0;
        mmat[1][3] = 0.0;

        mmat[2][0] = 0.0;
        mmat[2][1] = 0.0;
        mmat[2][2] = 1.0;
        mmat[2][3] = 0.0;

        mmat[3][0] = 0.0;
        mmat[3][1] = 0.0;
        mmat[3][2] = 0.0;
        mmat[3][3] = 1.0;
        matrixmult(mmat, mat, mat);
    }

    /*
    *    zshear -
    *        shear z using x and y.
    */
    inline void zshearmat(float mat[4][4], float dx, float dy)
    {
        float mmat[4][4];

        mmat[0][0] = 1.0;
        mmat[0][1] = 0.0;
        mmat[0][2] = dx;
        mmat[0][3] = 0.0;

        mmat[1][0] = 0.0;
        mmat[1][1] = 1.0;
        mmat[1][2] = dy;
        mmat[1][3] = 0.0;

        mmat[2][0] = 0.0;
        mmat[2][1] = 0.0;
        mmat[2][2] = 1.0;
        mmat[2][3] = 0.0;

        mmat[3][0] = 0.0;
        mmat[3][1] = 0.0;
        mmat[3][2] = 0.0;
        mmat[3][3] = 1.0;
        matrixmult(mmat, mat, mat);
    }

    /*
    *    simplehuerotatemat -
    *        simple hue rotation. This changes luminance
    */
    inline void simplehuerotatemat(float mat[4][4], float rot)
    {
        cocos2d::log("************* simplehuerotatemat");

        float mag;
        float xrs, xrc;
        float yrs, yrc;
        float zrs, zrc;
        identmat((float*)mat);

        /* rotate the grey vector into positive Z */
        mag = sqrt(2.0);
        xrs = 1.0 / mag;
        xrc = 1.0 / mag;
        xrotatemat(mat, xrs, xrc);
        //printmat(mat);

        mag = sqrt(3.0);
        yrs = -1.0 / mag;
        yrc = sqrt(2.0) / mag;
        yrotatemat(mat, yrs, yrc);
        //printmat(mat);

        /* rotate the hue */
        zrs = sin(rot);
        zrc = cos(rot);
        zrotatemat(mat, zrs, zrc);
        //printmat(mat);

        /* rotate the grey vector back into place */
        yrotatemat(mat, -yrs, yrc);
        // printmat(mat);
        xrotatemat(mat, -xrs, xrc);
        //printmat(mat);

        cocos2d::log("############## simplehuerotatemat");
    }

    /*
    *    huerotatemat -
    *        rotate the hue, while maintaining luminance.
    */
    inline void huerotatemat(float mat[4][4], float rot)
    {
        float mmat[4][4];
        float mag;
        float lx, ly, lz;
        float xrs, xrc;
        float yrs, yrc;
        float zrs, zrc;
        float zsx, zsy;

        identmat((float*)mat);
        identmat((float*)&mmat);

        /* rotate the grey vector into positive Z */
        mag = sqrt(2.0);
        xrs = 1.0 / mag;
        xrc = 1.0 / mag;
        xrotatemat(mmat, xrs, xrc);
        mag = sqrt(3.0);
        yrs = -1.0 / mag;
        yrc = sqrt(2.0) / mag;
        yrotatemat(mmat, yrs, yrc);

        /* shear the space to make the luminance plane horizontal */
        xformpnt(mmat, RLUM, GLUM, BLUM, &lx, &ly, &lz);
        zsx = lx / lz;
        zsy = ly / lz;
        zshearmat(mmat, zsx, zsy);

        /* rotate the hue */
        zrs = sin(rot);
        zrc = cos(rot);
        zrotatemat(mmat, zrs, zrc);

        /* unshear the space to put the luminance plane back */
        zshearmat(mmat, -zsx, -zsy);

        /* rotate the grey vector back into place */
        yrotatemat(mmat, -yrs, yrc);
        xrotatemat(mmat, -xrs, xrc);

        matrixmult(mmat, mat, mat);
    }

    /*
    *    xformpnt -
    *        transform a 3D point using a matrix
    */
    inline void xformpnt(Matrix3f* matrix, float x, float y, float z, float *tx, float *ty, float *tz)
    {
        *tx = x*matrix->m[0] + y*matrix->m[3] + z*matrix->m[6];
        *ty = x*matrix->m[1] + y*matrix->m[4] + z*matrix->m[7];
        *tz = x*matrix->m[2] + y*matrix->m[5] + z*matrix->m[8];
    }

    /*
    *    zshear -
    *        shear z using x and y.
    */
    inline void zshearmat(Matrix3f* mat, float dx, float dy)
    {
        // float mmat[4][4];
        Matrix3f mmat;
        //mmat[0][0] = 1.0;
        //mmat[0][1] = 0.0;
        mmat.m[2] = dx;
        //mmat[0][3] = 0.0;

        //mmat[1][0] = 0.0;
        //mmat[1][1] = 1.0;
        mmat.m[5] = dy;
        //mmat[1][3] = 0.0;

        //mmat[2][0] = 0.0;
        //mmat[2][1] = 0.0;
        //mmat[2][2] = 1.0;
        //mmat[2][3] = 0.0;

        //mmat[3][0] = 0.0;
        //mmat[3][1] = 0.0;
        //mmat[3][2] = 0.0;
        //mmat[3][3] = 1.0;
        mat->mult(mmat);//matrixmult(mmat, mat, mat);
    }

    inline void createHueMatrix(cocos2d::Mat4* dst, float angle)
    {
        cocos2d::log("************* createHueMatrix4f");

        memcpy(dst, &dst->IDENTITY, sizeof(*dst));

        /* rotate the grey vector into positive Z */
        createRotationX(dst, FLT_XRS, FLT_XRC);// rotateX(dst, FLT_XRS, FLT_XRC);
        rotateY(dst, FLT_YRS, FLT_YRC);

        /* rotate the hue */
        rotateZ(dst, angle);

        /* rotate the grey vector back into place */
        rotateY(dst, -FLT_YRS, FLT_YRC);
        rotateX(dst, -FLT_XRS, FLT_XRC);

        cocos2d::log("############## createHueMatrix4f");
    }

    inline void setMatrixHueOptimized(Matrix3f* dst, float angle)
    {
        float lx, ly, lz;
        float zsx, zsy;
        // memcpy(dst, &dst->IDENTITY, sizeof(*dst));

        /* rotate the grey vector into positive Z */
        dst->createRotationX(FLT_XRS, FLT_XRC);// rotateX(dst, FLT_XRS, FLT_XRC);
        dst->rotateY(FLT_YRS, FLT_YRC);

        /* shear the space to make the luminance plane horizontal */
        xformpnt(dst, RLUM, GLUM, BLUM, &lx, &ly, &lz);
        zsx = lx / lz;
        zsy = ly / lz;
        zshearmat(dst, zsx, zsy);

        /* rotate the hue */
        dst->rotateZ(angle);

        /* unshear the space to put the luminance plane back */
        zshearmat(dst, -zsx, -zsy);

        /* rotate the grey vector back into place */
        dst->rotateY(-FLT_YRS, FLT_YRC);
        dst->rotateX(-FLT_XRS, FLT_XRC);
    }

    /*
    *    Hue -
    *        HSV - H
    */
    inline void setMatrixHue(Matrix3f* dst, float angle)
    {
        cocos2d::log("************* createHueMatrix3f");

        // memcpy(dst, &dst->IDENTITY, sizeof(*dst));

        /* rotate the grey vector into positive Z */
        dst->createRotationX(FLT_XRS, FLT_XRC);// rotateX(dst, FLT_XRS, FLT_XRC);
        dst->rotateY(FLT_YRS, FLT_YRC);

        /* rotate the hue */
        dst->rotateZ(angle);

        /* rotate the grey vector back into place */
        dst->rotateY(-FLT_YRS, FLT_YRC);
        dst->rotateX(-FLT_XRS, FLT_XRC);

        cocos2d::log("############## createHueMatrix3f");
    }

    /*
    *    saturatemat - 0~1, 0%~100% ?
    *        HSV - S
    */
    inline void setMatrixSat(Matrix3f* dst, float sat)
    {
        Matrix3f temp;
        float a, b, c, d, e, f, g, h, i;
        float rwgt, gwgt, bwgt;

        rwgt = RLUM;
        gwgt = GLUM;
        bwgt = BLUM;

        a = (1.0 - sat)*rwgt + sat;
        b = (1.0 - sat)*rwgt;
        c = (1.0 - sat)*rwgt;
        d = (1.0 - sat)*gwgt;
        e = (1.0 - sat)*gwgt + sat;
        f = (1.0 - sat)*gwgt;
        g = (1.0 - sat)*bwgt;
        h = (1.0 - sat)*bwgt;
        i = (1.0 - sat)*bwgt + sat;
        temp.m[0] = a;
        temp.m[1] = b;
        temp.m[2] = c;
        // mmat[0][3] = 0.0;

        temp.m[3] = d;
        temp.m[4] = e;
        temp.m[5] = f;
        //mmat[1][3] = 0.0;

        temp.m[6] = g;
        temp.m[7] = h;
        temp.m[8] = i;
        // mmat[2][3] = 0.0;

        //mmat[3][0] = 0.0;
        //mmat[3][1] = 0.0;
        //mmat[3][2] = 0.0;
        //mmat[3][3] = 1.0;
        // matrixmult(mmat, mat, mat);
        dst->mult(temp);
    }

    /* Value
    *    HSV - V: 0~1, 0%, 100%
    */
    inline void setMatrixVal(Matrix3f* dst, float value)
    {
        // float mmat[4][4];
        Matrix3f temp;
        temp.m[0] = value;
        //temp.m[1] = 0.0;
        //temp.m[2] = 0.0;
        //mmat[0][3] = 0.0;

        //mmat[1][0] = 0.0;
        temp.m[4] = value;
        // mmat[1][2] = 0.0;
        //mmat[1][3] = 0.0;


        //mmat[2][0] = 0.0;
        //mmat[2][1] = 0.0;
        temp.m[8] = value;
        //mmat[2][3] = 0.0;

        dst->mult(temp);
        // matrixmult(mmat, mat, mat);
    }

    bool enableNodeIntelliShading(cocos2d::Node* node,
        bool noMVP,
        const cocos2d::Vec3& hsv,
        const cocos2d::Vec3& filter = cocos2d::Vec3(1.0f, 0.45f, 0.3109),
        bool forceShading = false,
        const cocos2d::Vec3& hsvShading = cocos2d::Vec3::ZERO);

    void updateNodeHsv(cocos2d::Node* node,
        const cocos2d::Vec3& hsv, 
        const cocos2d::Vec3& filter = cocos2d::Vec3(1.0f, 0.45f, 0.3109), 
        bool forceShading = false, 
        const cocos2d::Vec3& hsvShading = cocos2d::Vec3::ZERO);

    cocos2d::GLProgram* addPositionTextureColorGLProgram(const std::string& fragFile, bool noMVP, bool refresh = false);
};

#endif
